﻿using System;
using System.Collections.Generic;
using System.Text;

namespace CentrifugalSealCalc
{
    public class Calc
    {
        public double SpecificGravity = 1.3;           // user input e.g. 1.3
        public double SuctionHead = 2;           // user input e.g. 2 m

        private Outputs _outputs = new Outputs();

        private Impeller _impeller = new Impeller();
        private Expeller _expeller = new Expeller();

        public Calc(Impeller impeller, Expeller expeller)
        {
            this._impeller = impeller;
            this._expeller = expeller;
        }

        public Outputs Start()
        {
            _impeller.K = GetK(_impeller.T, _impeller.C);
            _expeller.K = GetK(_expeller.T, _expeller.C);

            _outputs.Pinlet = SpecificGravity * SuctionHead * 9.8605 * 1000;
        
            double Pc = GetPressureCasing(_outputs.Pinlet);

            double PdropImp = GetPdropImp(_impeller.Ns);
            double PdropExp = GetPdropExp(_expeller.Ns);

            double Phub = Pc - PdropImp;
            double Pgland = Phub - PdropExp;

            _outputs.Pmax = PdropExp + PdropImp - Pc + _outputs.Pinlet;
            double Pc_max = GetPressureCasing(_outputs.Pmax);
            _outputs.Nd = Math.Sqrt(Pc / (GetPdropExp(1) + GetPdropImp(1)));

            _outputs.dr = _impeller.Ns / _outputs.Nd * _impeller.Ds;
            _outputs.percReduction = _outputs.dr / _impeller.Ds * 100; // RoundUp(_outputs.dr / _impeller.Ds * 100, 5);

            string diCode = string.Empty;
            switch ((int)RoundUp(_outputs.percReduction, 5))
            {
                case 95:
                    diCode = "B";
                    break;
                case 90:
                    diCode = "D";
                    break;
                case 85:
                    diCode = "F";
                    break;
                case 80:
                    diCode = "H";
                    break;
                case 75:
                    diCode = "J";
                    break;
                case 70:
                    diCode = "L";
                    break;
            }

            _outputs.MessageImepellerCode = string.Format("Use a Type {0} impeller.", diCode);
            _outputs.Safe = Pgland < 0;
            _outputs.Message = _outputs.Safe ? "Seal should not leak." : "Seal is leaking.";

            return _outputs;
        }

        public static int RoundUp(double i, int x)
        {
            // return i + (10 - i % 10); <-- logic error. Oops!
            return (int)(Math.Ceiling(i / (double)x) * x); // fixed
        }

        public double GetPressureCasing(double pressure)
        {
            return pressure + _impeller.A1 - _impeller.A2 * Math.Pow(_impeller.Q, _impeller.A3);
        }

        public double GetPdropImp(double speed)
        {
            return 5.48 * Math.Pow(_impeller.K, 2) * Math.Pow(speed, 2) * (Math.Pow(_impeller.R2, 2) - Math.Pow(_impeller.R1, 2));
        }

        public double GetPdropExp(double speed)
        {
            return 5.48 * Math.Pow(_expeller.K, 2) * Math.Pow(speed, 2) * (Math.Pow(_expeller.R2, 2) - Math.Pow(_expeller.R1, 2));
        }

        public double GetK(double T, double C)
        {
            return 0.7 + 0.3 * (T / (T + C));
        }
    }
}
